package com.zmn.mcc.task.job.staff;

import com.alibaba.fastjson.JSONObject;
import com.github.ltsopensource.core.domain.Action;
import com.github.ltsopensource.core.domain.Job;
import com.github.ltsopensource.spring.tasktracker.JobRunnerItem;
import com.github.ltsopensource.spring.tasktracker.LTS;
import com.github.ltsopensource.tasktracker.Result;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.manager.lts.interfaces.task.TaskManager;
import com.zmn.mcc.cas.CasConstants;
import com.zmn.mcc.cas.model.LoginStaff;
import com.zmn.mcc.cas.model.UserTokenDO;
import com.zmn.mcc.cas.web.LoginStaffBuilder;
import com.zmn.mcc.cas.web.dao.RedisSessionDao;
import com.zmn.mcc.common.constant.RedisConsts;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @author quanjic
 * @version v1.0
 * @since 2018/11/23 17:37
 **/
@LTS
public class StaffLoginJob {

    private Logger logger = LoggerFactory.getLogger(StaffLoginJob.class);

    /**
     * 描述: 员工在线列表维护任务
     */
    static final String TASK_ID_STAFF_ONLINE = "staffOnline";

    @Value("${cas.session.timeout:" + CasConstants.LOGIN_TIMEOUT_MILL + "}")
    private Long sessionTimeout;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TaskManager taskManager;

    @Autowired
    RedisSessionDao redisSessionDao;

    @PostConstruct
    void init() {
        Job job = new Job();
        job.setTaskId(TASK_ID_STAFF_ONLINE);
        job.setParam(TaskManager.SHARD_FIELD, TASK_ID_STAFF_ONLINE);
        //每五分钟执行一次
        job.setCronExpression("0 0/5 * * * ?");
        job.setReplaceOnExist(true);
        ResponseDTO<String> result = taskManager.submitTask2(job);
        if (!result.isSuccess()) {
            logger.error("#online_staff# job submit fail: {}", result.getMessage());
        }
    }

    /**
     * 维护在线员工列表
     *
     * @param job
     * @return
     * @throws Throwable
     */
    @JobRunnerItem(shardValue = TASK_ID_STAFF_ONLINE)
    public Result runStaffOnlineJob(Job job) throws Throwable {

        logger.debug("#job#online_staff#clean running...");


        long expire = System.currentTimeMillis() - sessionTimeout; //最后过期时间
//        Long cnt = redisTemplate.opsForZSet().removeRangeByScore(CasConstants.ONLINE_STAFF_KEY, 0, expire);
//        if (cnt != null && cnt > 0) {
//            logger.info("#job#online_staff#clean number:{}", cnt);
//        }
        Set set = redisTemplate.opsForZSet().rangeByScore(CasConstants.ONLINE_STAFF_KEY, 0, expire);
        int cnt = 0;
        for (Object sessionId : set) {
            try {
                Session session = redisSessionDao.readSession(sessionId.toString());
                LoginStaff loginStaff = null;
                if (Objects.nonNull(session)) {
                    loginStaff = doCurrentStaff(session);
                }
                if (Objects.nonNull(loginStaff)) {
                    redisTemplate.opsForHash().delete(RedisConsts.CAS_STAFF_SESSION, loginStaff.getStaffId().toString());
                }
            } catch (UnknownSessionException e) {
                continue;
            } finally {
                redisTemplate.opsForZSet().remove(CasConstants.ONLINE_STAFF_KEY, sessionId.toString());
                ++cnt;
            }
        }
        logger.info("#job#online_staff#clean number:{}", cnt);

        return new Result(Action.EXECUTE_SUCCESS, "清理离线人数:" + cnt);
    }

    private static LoginStaff doCurrentStaff(Session session) {
        if (session == null) {
            return null;
        } else {
            Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            if (obj == null) {
                return null;
            } else {
                if (obj instanceof SimplePrincipalCollection) {
                    SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
                    Object principal = spc.getPrimaryPrincipal();
                    if (principal != null && principal instanceof UserTokenDO) {
                        return LoginStaffBuilder.build((UserTokenDO) principal, session);
                    }

                    List list = spc.asList();
                    if (list.size() <= 1) {
                        return null;
                    }

                    obj = list.get(1);
                    if (obj instanceof JSONObject) {
                        UserTokenDO userTokenDO = (UserTokenDO) ((JSONObject) obj).getObject("userToken", UserTokenDO.class);
                        if (userTokenDO != null) {
                            return LoginStaffBuilder.build(userTokenDO, session);
                        }
                    }
                }

                return null;
            }
        }
    }

}
